﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Twodi.Structs
{
    /// <summary>
    /// Define a estrutura de um circulo.
    /// </summary>
    public struct Circle : IEquatable<Circle>
    {
        /// <summary>
        /// Centro do circulo.
        /// </summary>
        public Vector2 Center;

        /// <summary>
        /// Raio do circulo.
        /// </summary>
        public float Radius;

        /// <summary>
        /// Construtor padrão.
        /// </summary>
        /// <param name="x">Posição X do Circulo.</param>
        /// <param name="y">Posição Y do Circulo.</param>
        /// <param name="radius">Raio do Circulo.</param>
        public Circle(float x, float y, float radius)
        {
            this.Center = new Vector2(x, y);
            this.Radius = radius;
        }

        /// <summary>
        /// Construtor padrão.
        /// </summary>
        /// <param name="x">Posição X do Circulo.</param>
        /// <param name="y">Posição Y do Circulo.</param>
        /// <param name="radius">Raio do Circulo.</param>
        public Circle(int x, int y, int radius)
        {
            this.Center = new Vector2(x, y);
            this.Radius = radius;
        }

        /// <summary>
        /// Construtor padrão.
        /// </summary>
        /// <param name="center">Posição central do Circulo.</param>
        /// <param name="radius">Raio do Circulo.</param>
        public Circle(Vector2 center, float radius)
        {
            this.Center = center;
            this.Radius = radius;
        }

        /// <summary>
        /// Construtor padrão.
        /// </summary>
        /// <param name="center">Posição central do Circulo.</param>
        /// <param name="radius">Raio do Circulo.</param>
        public Circle(Point center, int radius)
        {
            this.Center = new Vector2(center.X, center.Y);
            this.Radius = radius;
        }

        /// <summary>
        /// Verificar se este circulo sobrepoe outro circulo.
        /// </summary>
        /// <param name="circle">Circulo a ser verificado.</param>
        /// <returns></returns>
        public bool Overlap(Circle circle)
        {
            float distance = Vector2.DistanceSquared(this.Center, circle.Center);
            float radiusSum = this.Radius + circle.Radius;
            return distance <= radiusSum * radiusSum;

        }

        /// <summary>
        /// Verificar se um ponto esta dentro de um circulo.
        /// </summary>
        /// <param name="x">Posição X.</param>
        /// <param name="y">Posição Y.</param>
        /// <returns></returns>
        public bool Overlap(float x, float y)
        {
            return Vector2.DistanceSquared(this.Center, new Vector2(x, y)) <= this.Radius * this.Radius;
        }

        /// <summary>
        /// Verificar se um ponto esta dentro de um circulo.
        /// </summary>
        /// <param name="point">Ponto a ser verificado.</param>
        /// <returns></returns>
        public bool Overlap(Vector2 point)
        {
            return Vector2.DistanceSquared(this.Center, point) <= this.Radius * this.Radius;
        }

        /// <summary>
        /// Verificar se um ponto esta dentro de um circulo.
        /// </summary>
        /// <param name="point">Ponto a ser verificado.</param>
        /// <returns></returns>
        public bool Overlap(Point point)
        {
            return Vector2.DistanceSquared(this.Center, new Vector2(point.X, point.Y)) <= this.Radius * this.Radius;
        }

        /// <summary>
        /// Verifica se um retangulo está dentro deste circulo.
        /// </summary>
        /// <param name="rectangle">Retangulo a ser verificado.</param>
        /// <returns></returns>
        public bool Overlap(Rectangle rectangle)
        {
            Vector2 circleDistance = new Vector2();

            float halfWidht = rectangle.Width / 2;
            float halfHeight = rectangle.Height / 2;

            circleDistance.X = Math.Abs(Center.X - rectangle.X - halfWidht);
            circleDistance.Y = Math.Abs(Center.Y - rectangle.Y - halfHeight);

            if (circleDistance.X > (halfWidht + this.Radius))
            {
                return false;
            }

            if (circleDistance.Y > (halfHeight + this.Radius))
            {
                return false;
            }

            float valueX = (circleDistance.X - halfWidht);
            float valueY = (circleDistance.Y - halfHeight);

            float cornerDistance_sq = (valueX * valueX) + (valueY * valueY);

            return (cornerDistance_sq <= (Radius * Radius));
        }

        /// <summary>
        /// Verificar equalidade com outro circulo.
        /// </summary>
        /// <param name="other">Circulo a ser verificado.</param>
        /// <returns></returns>
        public bool Equals(Circle other)
        {
            return this.Center == other.Center && this.Radius == other.Radius;
        }

        /// <summary>
        /// Verificar equalidade com outro circulo.
        /// </summary>
        /// <param name="value1">Circulo A a ser verificado.</param>
        /// <param name="value2">Circulo B a ser verificado.</param>
        /// <returns></returns>
        public static bool operator ==(Circle value1, Circle value2)
        {
            return value1.Center == value2.Center && value1.Radius == value2.Radius;
        }

        /// <summary>
        /// Verificar diferença com outro circulo.
        /// </summary>
        /// <param name="value1">Circulo A a ser verificado.</param>
        /// <param name="value2">Circulo B a ser verificado.</param>
        /// <returns></returns>
        public static bool operator !=(Circle value1, Circle value2)
        {
            return value1.Center != value2.Center || value1.Radius != value2.Radius;
        }
    }
}
